package com.atom.app.mvvm.utils

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.IdRes
import androidx.recyclerview.widget.RecyclerView
import com.atom.module.mvvm.R
import java.util.*

abstract class AbstractAdapter<Data>
    : RecyclerView.Adapter<AbstractViewHolder<Data>>,
    View.OnClickListener, View.OnLongClickListener, AdapterCallback<Data> {

    private val mList: MutableList<Data> = ArrayList()
    private var mListener: AdapterListener<Data>? = null

    constructor() : this(null, null)

    constructor(listener: AdapterListener<Data>?) : this(null, listener)

    constructor(list: List<Data>?) : this(list, null)

    constructor(list: List<Data>?, listener: AdapterListener<Data>?) : super() {
        if (list != null) {
            mList.addAll(list)
        }
        mListener = listener
    }

    override fun onClick(v: View?) {
        if (v == null) return
        if (mListener == null) return
        val tag = v.getTag(R.id.tag_view_holder)
        if (tag is AbstractViewHolder<*>) {
            val temp = tag as AbstractViewHolder<Data>
            val adapterPosition = temp.adapterPosition
            if (adapterPosition < mList.size) {
                mListener?.onItemClick(v, this, temp, mList[adapterPosition])
            }
        }
    }

    override fun onLongClick(v: View?): Boolean {
        if (v == null) return false
        if (mListener == null) return false
        val tag = v.getTag(R.id.tag_view_holder)
        if (tag is AbstractViewHolder<*>) {
            val temp = tag as AbstractViewHolder<Data>
            val adapterPosition = temp.adapterPosition
            if (adapterPosition < mList.size) {
                mListener?.onItemLongClick(v, this, temp, mList[adapterPosition])
            }
        }
        return false
    }

    override fun getItemViewType(position: Int): Int {
        return getItemViewType(position, mList[position])
    }

    protected abstract fun getItemViewType(position: Int, data: Data): Int

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder<Data> {
        val inflate = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
        val viewHolder = onCreateViewHolder(inflate, viewType)
        inflate.setTag(R.id.tag_view_holder, viewHolder)
        inflate.setOnClickListener(this)
        inflate.setOnLongClickListener(this)
        viewHolder.callback = this
        return viewHolder
    }

    abstract fun onCreateViewHolder(contentView: View, viewType: Int): AbstractViewHolder<Data>

    override fun onBindViewHolder(holder: AbstractViewHolder<Data>, position: Int) {
        holder.bind(mList[position])
    }

    override fun getItemCount(): Int {
        return mList.size
    }

    open fun getItems(): List<Data>? {
        return mList
    }

    fun setAdapterListener(listener: AdapterListener<Data>) {
        this.mListener = listener
    }

    open fun add(data: Data) {
        mList.add(data)
        notifyItemInserted(mList.size - 1)
    }

    @SafeVarargs
    fun addAll(vararg array: Data) {
        if (array.isNotEmpty()) {
            val start = mList.size
            val offSet = array.size
            mList.addAll(listOf(*array))
            notifyItemRangeChanged(start, offSet)
        }
    }

    open fun addAll(collection: Collection<Data>) {
        if (collection.isNotEmpty()) {
            val start = mList.size
            val offSet = collection.size
            mList.addAll(collection)
            notifyItemRangeChanged(start, offSet)
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    open fun clear() {
        mList.clear()
        notifyDataSetChanged()
    }

    @SafeVarargs
    @SuppressLint("NotifyDataSetChanged")
    fun replaceAll(vararg array: Data) {
        if (array.isNotEmpty()) {
            mList.clear()
            mList.addAll(listOf(*array))
            notifyDataSetChanged()
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    open fun replaceAll(collection: Collection<Data>) {
        if (collection.isNotEmpty()) {
            mList.clear()
            mList.addAll(collection)
            notifyDataSetChanged()
        }
    }

    open fun replace(position: Int, data: Data) {
        val size = mList.size
        if (position in 1 until size) {
            // 进行数据的移除
            mList.removeAt(position)
            //更新
            mList.add(position, data)
            // 通知这个坐标下的数据有更新
            notifyItemChanged(position)
        }
    }

    override fun update(data: Data, viewHolder: AbstractViewHolder<Data>) {
        // 得到当前ViewHolder的坐标
        val pos = viewHolder.adapterPosition
        if (pos >= 0) {
            replace(pos, data)
        }
    }
}

abstract class AbstractViewHolder<Data>(itemView: View) : RecyclerView.ViewHolder(itemView) {

    var mData: Data? = null

    internal var callback: AdapterCallback<Data>? = null

    val views: MutableMap<Int, View> = HashMap()

    fun <T : View> view(@IdRes id: Int, pickView: (T)->Unit) {
        var view = views[id]
        if (view == null) {
            view = itemView.findViewById(id)
            views[id] = view
        }
        if (view == null) return
        pickView.invoke(view as T)
    }

    fun bind(data: Data) {
        mData = data
        onBind(data)
    }

    abstract fun onBind(data: Data)

    fun updateData(data: Data) {
        callback?.update(data, this)
    }
}

interface AdapterListener<Data> {
    fun onItemClick(
        view: View,
        adapter: AbstractAdapter<Data>,
        viewHolder: AbstractViewHolder<Data>,
        data: Data
    ) {
    }

    fun onItemLongClick(
        view: View,
        adapter: AbstractAdapter<Data>,
        viewHolder: AbstractViewHolder<Data>,
        data: Data
    ): Boolean = false
}

internal interface AdapterCallback<Data> {
    fun update(data: Data, viewHolder: AbstractViewHolder<Data>)
}
